package cn.gene.timeyan.security.sso.service.impl;


import cn.gene.timeyan.common.constant.RedisConstants;
import cn.gene.timeyan.common.exception.TimeyanServiceException;
import cn.gene.timeyan.common.pojo.domain.TimeyanAuthenticationInfo;
import cn.gene.timeyan.common.restful.JsonResult;
import cn.gene.timeyan.common.restful.ResponseCode;
import cn.gene.timeyan.common.utils.JwtTokenUtils;
import cn.gene.timeyan.common.utils.VerificationUtils;
import cn.gene.timeyan.pojo.admin.model.ConLog;
import cn.gene.timeyan.pojo.admin.vo.AdminVO;
import cn.gene.timeyan.pojo.ums.model.User;
import cn.gene.timeyan.pojo.ums.vo.UserVO;
import cn.gene.timeyan.pojo.valid.security.dto.UserCodeLoginDTO;
import cn.gene.timeyan.pojo.valid.security.dto.UserPassswordLoginDTO;
import cn.gene.timeyan.pojo.valid.security.dto.validateCodeDTO;
import cn.gene.timeyan.security.sso.mapper.admin.AdminMapper;
import cn.gene.timeyan.security.sso.mapper.admin.UserLoginLogMapper;
import cn.gene.timeyan.security.sso.mapper.user.UserMapper;
import cn.gene.timeyan.security.sso.pojo.vo.TokenVO;
import cn.gene.timeyan.security.sso.pojo.vo.UserInfoVO;
import cn.gene.timeyan.security.sso.service.IUserInfoService;
import cn.gene.timeyan.security.sso.service.IUserValidationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
 * UserInfoServiceImpl*
 *
 * @author LWG
 * @date 2022/7/22 16:28
 * @since 1.0.0@gene.cn
 */
@Service
@Slf4j
public class UserInfoServiceImpl implements IUserInfoService {
    @Autowired
    private JwtTokenUtils jwtTokenUtils;
    @Autowired(required = false)
    private AdminMapper adminMapper;
    @Autowired(required = false)
    private UserMapper userMapper;
    @Autowired
    IUserValidationService validationService;
    @Resource
    private VerificationUtils verificationUtils;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired(required = false)
    private UserLoginLogMapper userLoginLogMapper;
    private static final String jwtTokenHead ="Bearer";

    @Override
    public UserInfoVO userInfo(String authToken) {
        String token=authToken.substring(jwtTokenHead.length());
        log.info("获取token:{}",token);

        TimeyanAuthenticationInfo userInfo = jwtTokenUtils.getUserInfo(token);
        String type=userInfo.getUserType();
        Long id=userInfo.getId();
        //准备返回数据UserInfoVO
        UserInfoVO userInfoVO=new UserInfoVO();
        if (type!=null&&"ADMIN".equals(type)){
            AdminVO adminVO=adminMapper.findById(id);
            userInfoVO.setUserId(id);
            userInfoVO.setUsername(adminVO.getUserName());
        }else if(type!=null&&"USER".equals(type)){
            UserVO userVO=userMapper.findById(id);
            userInfoVO.setUserId(id);
            userInfoVO.setNickname(userVO.getNickname());
            userInfoVO.setPhone(userVO.getPhone());
            userInfoVO.setUsername(userVO.getPhone());
        }else{
            throw new TimeyanServiceException(ResponseCode.BAD_REQUEST,"无法获取用户信息");
        }
        return userInfoVO;
    }

    @Override
    public User loginByValidCode(validateCodeDTO validateCodeDTO) {
        return validationService.validateCode(validateCodeDTO);
    }

    @Override
    public JsonResult<TokenVO> userNameLogin(UserPassswordLoginDTO userPassswordLoginDTO) {
        String userName=userPassswordLoginDTO.getUsername();
        String password=userPassswordLoginDTO.getPassword();
        log.info("username"+userName);
        log.info("password"+password);
        //参数是否存在
        if (userPassswordLoginDTO==null||userName==null||password==null){
            log.info("参数为null");
            throw new TimeyanServiceException(ResponseCode.ERR_BAD_REQUEST,"用户名或密码错误");
        }
        //是否有该用户，密码是否正确
        User user=userMapper.findByUsernameAndPassword(userName,password);
        log.info("user"+user);
        if (user==null){
            log.info("数据库没有该用户");
            throw new TimeyanServiceException(ResponseCode.ERR_BAD_REQUEST,"用户名或密码错误");
        }
        //等于1，为正常账号
        log.info("user.getUserState()!=1"+(user.getUserState()!=1));
        if (user.getUserState()!=1){
            log.info("账号要么被封禁，要么已经注销");
            //账号要么被封禁，要么已经注销
            throw new TimeyanServiceException(ResponseCode.ERR_USER_NOT_FOUND,"账号已封禁或已注销，登录请联系客服");
        }
        //有信息,生成token传给前端
        TimeyanAuthenticationInfo info=new TimeyanAuthenticationInfo();
        info.setId(user.getUserId());
        info.setUsername(userName);
        info.setUserType("USER");
        String token = jwtTokenUtils.generateToken(info);
        log.info("token",token);
        //存登录日志
        ConLog userLoginLog=new ConLog();
        userLoginLog.setUserId(user.getUserId());
        LocalDateTime now=LocalDateTime.now();
        userLoginLog.setCreateTime(now);
        userLoginLog.setUpdateTime(now);
        userLoginLog.setLoginTime(now);
        userLoginLog.setIp(userPassswordLoginDTO.getIp());
        userLoginLog.setEquipment(userPassswordLoginDTO.getUserAgent());
        log.info("userLog"+userLoginLog);
        userLoginLogMapper.insertUserLoginLog(userLoginLog);
        //token封装
        TokenVO tokenVO = new TokenVO();
        tokenVO.setTokenHeader(jwtTokenHead);
        tokenVO.setTokenValue(token);
        return JsonResult.ok(tokenVO);
    }

    @Override
    public JsonResult<TokenVO> verificationLogin(UserCodeLoginDTO userCodeLoginDTO) {
        String resource=userCodeLoginDTO.getUsername();
        String code=userCodeLoginDTO.getCode();
        //参数是否存在
        if (userCodeLoginDTO==null||resource==null||code==null){
            log.info("参数为null");
            throw new TimeyanServiceException(ResponseCode.ERR_BAD_REQUEST,"登录凭证和验证码不能为空");
        }
        int flag=-1;
        //判断是手机号还是邮箱号
        if (verificationUtils.isPhone(resource)){
            //是手机号
            log.info("phone:"+resource);
            flag=0;
        }else if (verificationUtils.isEmail(resource)){
            log.info("email:"+resource);
            flag=1;
        }
        //获取缓存验证码
        String cacheCode=redisTemplate.opsForValue().get(RedisConstants.VERIFY_CODE_KEY+resource).toString();
        //是否过期
        if (cacheCode==null||cacheCode.isEmpty()){
            log.info("验证码已过期");
            throw new TimeyanServiceException(ResponseCode.ERR_VERIFICATION_CODE_VALUE,"验证码已过期，请重新发送");
        }
        //是否正确
        if (!cacheCode.equals(code)){
            log.info("验证码错误");
            throw new TimeyanServiceException(ResponseCode.ERR_BAD_REQUEST,"验证码输入错误");
        }
        //获取用户信息
        User user;
        if (flag==0){
            user=userMapper.findByPhone(resource);
        }else if(flag==1){
            user=userMapper.findByEmail(resource);
        }else{
            log.info("输入手机号或密码不合法");
            throw new TimeyanServiceException(ResponseCode.ERR_BAD_REQUEST,"手机号或邮箱号不合法");
        }
        log.info("user"+user);
        if (user==null){
            log.info("数据库没有该用户");
            throw new TimeyanServiceException(ResponseCode.ERR_BAD_REQUEST,"手机号或邮箱号错误");
        }
        //等于1，为正常账号
        log.info("user.getUserState()!=1"+(user.getUserState()!=1));
        if (user.getUserState()!=1){
            log.info("账号要么被封禁，要么已经注销");
            //账号要么被封禁，要么已经注销
            throw new TimeyanServiceException(ResponseCode.ERR_USER_NOT_FOUND,"账号已封禁或已注销，登录请联系客服");
        }
        //有信息,生成token传给前端
        TimeyanAuthenticationInfo info=new TimeyanAuthenticationInfo();
        info.setId(user.getUserId());
        info.setUsername(user.getUserName());
        info.setUserType("USER");
        String token = jwtTokenUtils.generateToken(info);
        log.info("token",token);
        ConLog userLoginLog=new ConLog();
        userLoginLog.setUserId(user.getUserId());
        LocalDateTime now=LocalDateTime.now();
        userLoginLog.setCreateTime(now);
        userLoginLog.setUpdateTime(now);
        userLoginLog.setLoginTime(now);
        userLoginLog.setIp(userCodeLoginDTO.getIp());
        userLoginLog.setEquipment(userCodeLoginDTO.getUserAgent());
        userLoginLogMapper.insertUserLoginLog(userLoginLog);
        TokenVO tokenVO = new TokenVO();
        tokenVO.setTokenHeader(jwtTokenHead);
        tokenVO.setTokenValue(token);
        return JsonResult.ok(tokenVO);
    }

    @Value("${jwt.tokenHead}")
    private String tokenHead;//Bearer
    @Override
    public void doLogout(String token){
        if (token != null && token.startsWith(tokenHead)) {
            //拿到jwt token
            String authToken = token.substring(tokenHead.length());
            //写入redis 锁住 这里采用list分日期存储,方便后续定时清理
            String lockedTokenList="token_list_.lock";
            redisTemplate.boundSetOps(lockedTokenList).add(authToken);
            Long add = redisTemplate.boundSetOps(lockedTokenList).add(authToken);
            if(add==0){
                throw new TimeyanServiceException(ResponseCode.CONFLICT,"当前用户已经登出,不必重复登出");
            }
        }else{
            //header不存在token
            throw new TimeyanServiceException(ResponseCode.NOT_FOUND,"当前客户端没有登录状态");
        }
    }

}
